package com.dfch.auto.appium.main;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dfch.auto.appium.pool.AutoThreadPool;
import com.dfch.auto.appium.utils.*;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.AndroidElement;
import io.appium.java_client.remote.AndroidMobileCapabilityType;
import io.appium.java_client.remote.AutomationName;
import io.appium.java_client.remote.MobileCapabilityType;
import org.openqa.selenium.Platform;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * @author ldcmaxim on 06/04/2018.
 */
public class AutoMainFrame extends JFrame implements ActionListener {
    private static final Logger LOGGER = LoggerFactory.getLogger(AutoMainFrame.class);
    private static String[] PARAM_KEYS = {"platform_version", "device_name", "package", "activity", "url"};

    // 授权码
    private JTextField mTfAuthCode;
    private JLabel mLbScriptId;
    private String mScriptId;
    private String mScript;
    // 刷新
    private JButton mBtnRefresh;
    // 执行
    private JButton mBtnExecute;
    // 脚本
    private JLabel mLbScript;
    private JComboBox<String> mCobScript;
    private DefaultListModel mDeviceModel = new DefaultListModel();
    // 脚本循环次数
    private JLabel mLbTimes;
    private JTextField mTfTimes;
    private int mTimes;
    // 评论
    private JLabel mLbComment;
    private JCheckBox mCkbComment;
    private JTextField mTfComment1;
    private JTextField mTfComment2;
    private JTextField mTfComment3;
    private boolean mIsComment = false;
    private String mComment1;
    private String mComment2;
    private String mComment3;
    // 表情包
    private JLabel mLbFace;
    private JTextField mTfFace;
    private String mFace;
    // 设备列表
    private JScrollPane mSpDeviceList;
    private JList<String> mLsDeviceList;
    private JCheckBox mCkbSelectAll;
    private JCheckBox mCkbSelectNone;
    private JButton mBtnSearch;
    private boolean mIsSelectAll = false;
    private boolean mIsSelectNone = false;


    public AutoMainFrame() {

        initConfig();

        initView();

        initListener();

        initData();
    }

    private void initConfig() {
        // 标题
        setTitle("大风创合引流脚本");
        // 窗口大小固定480x640
        setSize(640, 480);
        // 窗口大小不可改变
        setResizable(false);
        // 窗口居中
        setLocationRelativeTo(null);
        // 关闭窗口时退出程序
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }

    private void initView() {
        Container container = getContentPane();
        // 取消布局管理器,采用绝对布局
        container.setLayout(null);

        mLbScriptId = new JLabel();
        mLbScriptId.setBounds(70, 10, 50, 34);
        mLbScriptId.setHorizontalAlignment(SwingConstants.LEFT);
        container.add(mLbScriptId);
        mLbScriptId.setText("授权码:");


        mTfAuthCode = new JTextField();
        mTfAuthCode.setBounds(120, 11, 280, 32);
        container.add(mTfAuthCode);
        mScriptId = "089c3a1e3f3542338b2c6200fc67e7eb";
        mTfAuthCode.setText(mScriptId);

        mBtnRefresh = new JButton("刷新");
        mBtnRefresh.setBounds(410, 10, 80, 34);
        container.add(mBtnRefresh);
        mBtnRefresh.setEnabled(false);

        mBtnExecute = new JButton("执行");
        mBtnExecute.setBounds(490, 10, 80, 34);
        container.add(mBtnExecute);

        mLbScript = new JLabel();
        mLbScript.setBounds(70, 50, 50, 38);
        mLbScript.setHorizontalAlignment(SwingConstants.LEFT);
        container.add(mLbScript);
        mLbScript.setText("脚本:");

        String[] script = {"抖音(Android)引流脚本", "抖音(iOS)引流脚本", "微信(Android)引流脚本", "微信(iOS)引流脚本"};
        mCobScript = new JComboBox<String>(script);
        mCobScript.setBounds(120, 50, 280, 38);
        container.add(mCobScript);

        mLbTimes = new JLabel();
        mLbTimes.setBounds(410, 50, 60, 38);
        mLbTimes.setHorizontalAlignment(SwingConstants.LEFT);
        container.add(mLbTimes);
        mLbTimes.setText("循环次数:");

        mTfTimes = new JTextField();
        mTfTimes.setBounds(480, 53, 90, 32);
        mTfTimes.setHorizontalAlignment(SwingConstants.CENTER);
        mTfTimes.setEnabled(false);
        container.add(mTfTimes);
        mTfTimes.setText("100");

        mLbComment = new JLabel();
        mLbComment.setBounds(70, 90, 38, 38);
        mLbComment.setHorizontalAlignment(SwingConstants.LEFT);
        container.add(mLbComment);
        mLbComment.setText("评论");

        mCkbComment = new JCheckBox();
        mCkbComment.setBounds(95, 94, 30, 30);
        mCkbComment.setHorizontalAlignment(SwingConstants.LEFT);
        container.add(mCkbComment);
        mCkbComment.setText("");

        mTfComment1 = new JTextField();
        mTfComment1.setBounds(120, 93, 150, 32);
        mTfComment1.setHorizontalAlignment(SwingConstants.LEFT);
        mTfComment1.setEnabled(false);
        container.add(mTfComment1);

        mTfComment2 = new JTextField();
        mTfComment2.setBounds(270, 93, 150, 32);
        mTfComment2.setHorizontalAlignment(SwingConstants.LEFT);
        mTfComment2.setEnabled(false);
        container.add(mTfComment2);

        mTfComment3 = new JTextField();
        mTfComment3.setBounds(420, 93, 150, 32);
        mTfComment3.setHorizontalAlignment(SwingConstants.LEFT);
        mTfComment3.setEnabled(false);
        container.add(mTfComment3);

        mLbFace = new JLabel();
        mLbFace.setBounds(70, 130, 50, 34);
        mLbFace.setHorizontalAlignment(SwingConstants.LEFT);
        container.add(mLbFace);
        mLbFace.setText("表情包:");

        mTfFace = new JTextField();
        mTfFace.setBounds(120, 129, 450, 32);
        mTfFace.setHorizontalAlignment(SwingConstants.LEFT);
        container.add(mTfFace);

        mSpDeviceList = new JScrollPane();
        mSpDeviceList.setBorder(BorderFactory.createTitledBorder("请选择连接设备"));
        mSpDeviceList.setBounds(70, 170, 500, 240);
        mLsDeviceList = new JList<String>();
        mLsDeviceList.setCellRenderer(new DeviceCellRender());
        mLsDeviceList.setModel(mDeviceModel);
        mSpDeviceList.setViewportView(mLsDeviceList);
        container.add(mSpDeviceList);

        mCkbSelectAll = new JCheckBox();
        mCkbSelectAll.setBounds(66, 410, 60, 30);
        container.add(mCkbSelectAll);
        mCkbSelectAll.setText("全选");

        mCkbSelectNone = new JCheckBox();
        mCkbSelectNone.setBounds(120, 410, 60, 30);
        container.add(mCkbSelectNone);
        mCkbSelectNone.setText("反选");

        mBtnSearch = new JButton();
        mBtnSearch.setBounds(180, 412, 80, 28);
        container.add(mBtnSearch);
        mBtnSearch.setText("搜索设备");
    }

    private void initListener() {
        mBtnRefresh.addActionListener(this);
        mBtnExecute.addActionListener(this);
        mBtnSearch.addActionListener(this);

//        mLsDeviceList.addListSelectionListener(new ListSelectionListener() {
//            @Override
//            public void valueChanged(ListSelectionEvent e) {
//                int index = mLsDeviceList.getSelectedIndex();
//                CellInfo info = (CellInfo) mDeviceModel.getElementAt(index);
//                info.setIsChecked(!info.isChecked());
//            }
//        });
        // 评论
        mCkbComment.addActionListener(this);
        // 全选 反选
        mCkbSelectAll.addActionListener(this);
        mCkbSelectNone.addActionListener(this);
    }

    private void initData() {
        // 搜索设备
        searchDevice();


    }

    // 保存数据
    private void saveData() {
        // 授权码
        mScriptId = mTfAuthCode.getText().trim();
        // 脚本循环次数
        String times = mTfTimes.getText().trim();
        mTimes = !TextUtils.isEmpty(times) ? Integer.parseInt(times) : 0;
        // 评论
        mIsComment = mCkbComment.isSelected();
        mComment1 = mTfComment1.getText().trim();
        mComment2 = mTfComment2.getText().trim();
        mComment3 = mTfComment3.getText().trim();
        // 表情包
        mFace = mTfFace.getText().trim();
        // 全选 反选
        mIsSelectAll = mCkbSelectAll.isSelected();
        mIsSelectNone = mCkbSelectNone.isSelected();
    }

    // 恢复数据
    private void restoreData() {
        // 授权码
        mTfAuthCode.setText(!TextUtils.isEmpty(mScriptId) ? mScriptId : "");
        // 评论
        mCkbComment.setSelected(mIsComment);
        mTfComment1.setText(!TextUtils.isEmpty(mComment1) ? mComment1 : "");
        mTfComment2.setText(!TextUtils.isEmpty(mComment2) ? mComment2 : "");
        mTfComment3.setText(!TextUtils.isEmpty(mComment3) ? mComment3 : "");
    }


    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == mBtnRefresh) {
            saveData();

            initData();
            // 获得容器
            Container c = getContentPane();
            // 设置容器背景颜色
            c.setBackground(Color.BLUE);
        } else if (e.getSource() == mBtnExecute) {
            mScriptId = mTfAuthCode.getText().trim();
            if (TextUtils.isEmpty(mScriptId)) {
                JOptionPane.showMessageDialog(this, "请输入授权码", "提示", JOptionPane.WARNING_MESSAGE);
                return;
            }

            List<String> devices = new LinkedList<>();
            for (int i = 0; i < mDeviceModel.size(); ++i) {
                CellInfo info = (CellInfo) mDeviceModel.getElementAt(i);
                if (info.isChecked()) {
                    devices.add(info.getDevice());
                }
            }

            if (devices.isEmpty()) {
                JOptionPane.showMessageDialog(this, "请选择连接设备", "提示", JOptionPane.WARNING_MESSAGE);
                return;
            }

            runScript(mScriptId, devices);
        }
        // 评论
        else if (e.getSource() == mCkbComment) {
            if (mCkbComment.isSelected()) {
                mTfComment1.setEnabled(true);
                mTfComment2.setEnabled(true);
                mTfComment3.setEnabled(true);
            } else {
                mTfComment1.setEnabled(false);
                mTfComment2.setEnabled(false);
                mTfComment3.setEnabled(false);
            }
        } else if (e.getSource() == mCkbSelectAll) {
            mCkbSelectAll.setSelected(true);
            mCkbSelectNone.setSelected(false);
            for (int i = 0; i < mDeviceModel.size(); ++i) {
                CellInfo info = (CellInfo) mDeviceModel.getElementAt(i);
                info.setIsChecked(true);
            }
            mLsDeviceList.updateUI();
        } else if (e.getSource() == mCkbSelectNone) {
            mCkbSelectAll.setSelected(false);
            mCkbSelectNone.setSelected(true);
            mLsDeviceList.clearSelection();
            for (int i = 0; i < mDeviceModel.size(); ++i) {
                CellInfo info = (CellInfo) mDeviceModel.getElementAt(i);
                info.setIsChecked(false);
            }
            mLsDeviceList.updateUI();
        } else if (e.getSource() == mBtnSearch) {
            mCkbSelectAll.setSelected(false);
            mIsSelectAll = false;
            mCkbSelectNone.setSelected(false);
            mIsSelectNone = false;
            // 搜索设备
            searchDevice();
        }
    }

    class CellInfo {
        private boolean mIsChecked;
        private String mDevice;

        public CellInfo(String device) {
            this(false, device);
        }

        public CellInfo(boolean isChecked, String device) {
            this.mIsChecked = isChecked;
            this.mDevice = device;
        }

        public void setIsChecked(boolean isChecked) {
            this.mIsChecked = isChecked;
        }

        public boolean isChecked() {
            return this.mIsChecked;
        }

        public void setDevice(String device) {
            this.mDevice = device;
        }

        public String getDevice() {
            return this.mDevice;
        }

        @Override
        public String toString() {
            return "Device:" + mDevice + ", IsChecked:" + mIsChecked;
        }
    }

    class DeviceCellRender extends JCheckBox implements ListCellRenderer {

        @Override
        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            AutoMainFrame.CellInfo info = (AutoMainFrame.CellInfo) value;
            this.setText(info.getDevice());
            this.setSelected(info.isChecked());
            return this;
        }
    }

    private void searchDevice() {
        AutoThreadPool.getInstance().executeAsyncTask(new Runnable() {
            @Override
            public void run() {
                final List<String> deviceList = ADBUtil.getDevices();
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        if (deviceList == null || deviceList.isEmpty()) {
                            return;
                        }
                        // 清除旧数据
                        mDeviceModel.clear();
                        for (String device : deviceList) {
                            mDeviceModel.addElement(new CellInfo(device));
                        }
                        mLsDeviceList.updateUI();
                    }
                });
            }
        });
    }

    private void runScript(final String scriptId, final List<String> devices) {
        AutoThreadPool.getInstance().executeAsyncTask(new Runnable() {
            @Override
            public void run() {
                try {
                    try {
                        AppiumUtils.destoryAll(devices, 6000);

                        AppiumUtils.createAppiumServers(devices, 6000);
                        LOGGER.debug("脚本启动参数:{}", JSON.toJSONString(scriptId));
                    } catch (IOException e) {
                        LOGGER.error("创建appium服务器失败:", e);
                    }

                    Thread.sleep(3000);

                    String response = RequestUtil.send("http://47.100.41.110:18000/as/get?sid=" + scriptId, null, "utf-8");
                    System.out.println(response);
                    JSONObject paramMap = JSON.parseObject(response);
                    if (!paramMap.get("result").equals("0")) {
                        throw new RuntimeException("获取脚本失败:" + paramMap.get("msg"));
                    }

                    JSONObject scriptObject = (JSONObject) paramMap.get("data");
                    LOGGER.info("正在执行脚本:{}", scriptObject.get("name"));

                    for (String key : PARAM_KEYS) {
                        if (key.equals("device_name")) {
                            continue;
                        }
                        if (scriptObject.containsKey(key) == false) {
                            throw new RuntimeException("脚本缺少基础配置项:" + key);
                        }
                    }

                    CountDownLatch cdl = new CountDownLatch(devices.size());
                    AndroidCMDUtil util = new AndroidCMDUtil();
                    int startPort = 6000;
                    for (final String device : devices) {
                        startPort++;
                        final Integer tempPort = startPort;
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                Integer loop = (Integer) scriptObject.get("loop");
                                loop = loop == null ? 1 : loop;
                                Integer step = 0;
                                Long now = System.currentTimeMillis();

                                try {
                                    AndroidDriver<AndroidElement> driver = initDriver(scriptObject.get(PARAM_KEYS[0]).toString(), device, scriptObject.get(PARAM_KEYS[2]).toString(), scriptObject.get(PARAM_KEYS[3]).toString(), "http://127.0.0.1:" + tempPort + "/wd/hub");
                                    JSONArray steps = (JSONArray) scriptObject.get("steps");


                                    while (step < loop) {
                                        for (Object stepCMD : steps) {
                                            Long snow = System.currentTimeMillis();
                                            try {
                                                JSONObject actionObject = (JSONObject) stepCMD;
                                                String action = (String) actionObject.get("action");
                                                String selector = (String) actionObject.get("selector");
                                                JSONArray targets = (JSONArray) actionObject.get("targets");
                                                JSONArray params = (JSONArray) actionObject.get("params");
                                                util.execute(driver, action, selector, targets, params);
                                            } catch (Exception ex) {
                                                LOGGER.error("执行脚本流程中发生错误,跳过此次操作!");
                                            }
                                            LOGGER.info("执行一次 脚本结束,耗时:{}s", new BigDecimal(snow / 1000).doubleValue());
                                        }
                                        step++;
                                    }
//                            new TouchAction(driver).release();
                                } catch (Exception ex) {
                                    LOGGER.info("脚本执行发生错误", ex);
                                } finally {
                                    cdl.countDown();
                                }
                                LOGGER.info("脚本执行再设备{}上执行{}次,总耗时:{}ms", scriptObject.get(PARAM_KEYS[1]).toString(), loop, System.currentTimeMillis() - now);
                            }
                        }).start();
                    }

                    cdl.await();
                    LOGGER.info("脚本执行结束，正在回收进程");
                    AppiumUtils.destoryAll(devices, 6000);

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private static AndroidDriver initDriver(String PLATFORM_VERSION, String DEVICE_NAME, String APP_PACKAGE, String APP_ACTIVITY, String APPIUM_SERVER) throws Exception {
        //System.out.println("Hello world!");
        DesiredCapabilities capabilities = new DesiredCapabilities();
        // Platform
        capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, Platform.ANDROID);
        // Android system version
        //capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.0");
        capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, PLATFORM_VERSION);
        // Adb device name
        // capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "36a98632");
        capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, DEVICE_NAME);
        // Reset app and clear cache
        capabilities.setCapability(MobileCapabilityType.NO_RESET, true);
        // Application package name
        capabilities.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, APP_PACKAGE);
        // Application activity name
        capabilities.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, APP_ACTIVITY);
        // Unicode keyboard
        capabilities.setCapability(AndroidMobileCapabilityType.UNICODE_KEYBOARD, true);
        // Hide keyboard
        capabilities.setCapability(AndroidMobileCapabilityType.RESET_KEYBOARD, true);
        // Set automation type
        capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.APPIUM);

        AndroidDriver<AndroidElement> driver = new AndroidDriver<>(new URL(APPIUM_SERVER), capabilities);
        //启动后等待视频加载

        Thread.sleep(3000);

        return driver;
    }
}
